package oen.game.csv.loader.util;

import im.oen.boot.common.utils.Checker;
import im.oen.boot.common.utils.Convert;
import im.oen.boot.common.utils.JsonUtil;
import oen.game.csv.loader.data.FieldData;

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.math.BigDecimal;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * <p>描述：字段值类型转换器</p>
 *
 * <p>创建时间：2021-11-09 12:35</p>
 * <p>更新时间：暂无</p>
 *
 * @author Kevin.Xu
 * @version 1.0
 */
public class FieldValueConvert {
    /**
     * <p>目前只支持：String,Integer,Short,Long,Double,BigDecimal,Boolean,List,Map</p>
     * <p>List 和 Map 的子对象只能是支持的基础类型</p>
     *
     * @param value     字符串值
     * @param fieldData 字段数据
     * @return 对象
     * @throws ClassNotFoundException 没找到数据类型
     */
    public static Object to(String value, FieldData fieldData) throws ClassNotFoundException {
        if (Checker.isEmpty(value)) {
            return null;
        }
        Type type = fieldData.getDeclaringType();
        String typeName = type.getTypeName();
        if (typeName.contains("<")) {
            typeName = typeName.substring(0, typeName.indexOf('<'));
        }
        Class<?> clazz = Class.forName(typeName);
        Object data = toBasic(value, clazz);
        if (data != null) {
            return data;
        }

        if (!(type instanceof ParameterizedType)) {
            return null;
        }

        ParameterizedType parameterizedType = (ParameterizedType) type;
        Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();

        if (clazz.equals(List.class)) {
            Class<?> actualTypeArgument = (Class<?>) actualTypeArguments[0];
            String[] values = value.split(fieldData.getSplitSymbol());
            if (Checker.isEmpty(values)) {
                return null;
            }
            return Stream.of(values).map(v -> toBasic(v, actualTypeArgument)).filter(v -> Checker.isNotEmpty(v)).collect(Collectors.toList());
        }

        if (Map.class.isAssignableFrom(clazz)) {
            Class<?> actualKeyTypeArgument = (Class<?>) actualTypeArguments[0];
            Class<?> actualValueTypeArgument = (Class<?>) actualTypeArguments[1];
            return JsonUtil.safeToMap(value, actualKeyTypeArgument, actualValueTypeArgument);
        }

        return null;
    }

    private static <T> T toBasic(String value, Class<T> clazz) {
        if (String.class.equals(clazz)) {
            return (T) value;
        }
        if (Short.class.equals(clazz)) {
            return (T) Convert.toShort(value);
        }
        if (Integer.class.equals(clazz)) {
            return (T) Convert.toInt(value);
        }
        if (Double.class.equals(clazz)) {
            return (T) Convert.toDouble(value);
        }
        if (BigDecimal.class.equals(clazz)) {
            return (T) Convert.toBigDecimal(value);
        }
        if (Boolean.class.equals(clazz)) {
            return (T) Convert.toBoolean(value);
        }
        return null;
    }
}
